﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Xml.Serialization;
using Microsoft.WowAddonStudio.FrameXml.Serialization.LayoutFrames;
using Microsoft.WowAddonStudio.FrameXml.Serialization.Support;

namespace Microsoft.WowAddonStudio.FrameXml.Serialization
{
    /// <summary>
    /// Acts as the root element of every FrameXML document.
    /// </summary>
    [Serializable]
    [DesignerCategory("code")]
    [XmlType(AnonymousType = true, Namespace = "http://www.blizzard.com/wow/ui/")]
    [XmlRoot(Namespace = "http://www.blizzard.com/wow/ui/", IsNullable = false)]
    public class Ui : SerializationObject, ISerializationObjectContainer
    {
        private readonly LayoutFrameList layoutFrames = new LayoutFrameList();
        private readonly List<Font> fonts = new List<Font>();

        public Ui()
        {
            InheritanceEnabled = true;
        }

        /// <summary>
        /// Gets or sets the <see cref="Include"/>s.
        /// </summary>
        [XmlElement("Include")]
        public Include[] Includes { get; set; }

        /// <summary>
        /// Gets or sets the <see cref="UiScript"/>s.
        /// </summary>
        [XmlElement("Script")]
		[Description("Retrieves lua scripts that contains this control.")]
        public UiScript[] Scripts { get; set; }

        /// <summary>
        /// Gets or sets the <see cref="Font"/>s.
        /// </summary>
        [XmlElement("Font")]
        [Browsable(false)]
        public List<Font> Fonts
        {
            get { return fonts; }
        }

        /// <summary>
        /// Gets or sets the <see cref="LayoutFrame"/>s.
        /// </summary>
        [XmlElement("LayoutFrame")]
        [XmlElement("Button", typeof(Button))]
        [XmlElement("CheckButton", typeof(CheckButton))]
        [XmlElement("ColorSelect", typeof(ColorSelect))]
        [XmlElement("Cooldown", typeof(Cooldown))]
        [XmlElement("DressUpModel", typeof(DressUpModel))]
        [XmlElement("EditBox", typeof(EditBox))]
        [XmlElement("FontString", typeof(FontString))]
        [XmlElement("Frame", typeof(Frame))]
        [XmlElement("GameTooltip", typeof(GameTooltip))]
        [XmlElement("MessageFrame", typeof(MessageFrame))]
        [XmlElement("Minimap", typeof(Minimap))]
        [XmlElement("Model", typeof(Model))]
        [XmlElement("ModelFFX", typeof(ModelFFX))]
        [XmlElement("MovieFrame", typeof(MovieFrame))]
        [XmlElement("PlayerModel", typeof(PlayerModel))]
        [XmlElement("ScrollFrame", typeof(ScrollFrame))]
        [XmlElement("ScrollingMessageFrame", typeof(ScrollingMessageFrame))]
        [XmlElement("SimpleHTML", typeof(SimpleHTML))]
        [XmlElement("Slider", typeof(Slider))]
        [XmlElement("StatusBar", typeof(StatusBar))]
        [XmlElement("TabardModel", typeof(TabardModel))]
        [XmlElement("TaxiRouteFrame", typeof(TaxiRouteFrame))]
        [XmlElement("Texture", typeof(Texture))]
        [XmlElement("WorldFrame", typeof(WorldFrame))]
        [Browsable(false)]
        public LayoutFrameList LayoutFrames
        {
            get { return layoutFrames; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether inheritance is enabled.
        /// </summary>
        /// <remarks>
        /// The value of this property is propagated to all children.
        /// </remarks>
        [XmlIgnore, Browsable(false)]
        public bool InheritanceEnabled { get; set; }

        /// <summary>
		/// Determines whether the container contains a serialization object.
		/// </summary>
		/// <param name="serializationObject">The serialization object.</param>
		/// <returns>
		/// True, if the container contains the serialization object; False otherwise.
		/// </returns>
        public bool Contains(SerializationObject serializationObject)
        {
            if (serializationObject is Font)
                return this.Fonts.Contains((Font)serializationObject);
            if (serializationObject is LayoutFrame)
                return this.LayoutFrames.Contains((LayoutFrame)serializationObject);

            return false;
        }

        /// <summary>
        /// Adds a serialization object.
        /// </summary>
        /// <param name="serializationObject">The serialization object.</param>
        void ISerializationObjectContainer.Add(SerializationObject serializationObject)
        {
            if (serializationObject == null)
                throw new ArgumentNullException("serializationObject");

            if (serializationObject is Font)
            {
                this.Fonts.Add((Font)serializationObject);
            }
            else
            {
                if (serializationObject is LayoutFrame)
                    this.LayoutFrames.Add((LayoutFrame) serializationObject);
                else
                    throw new ArgumentException("Serialization object cannot be added to this container.", "serializationObject");
            }
        }

        /// <summary>
        /// Removes a layout frame.
        /// </summary>
        /// <param name="serializationObject">The serialization object.</param>
        void ISerializationObjectContainer.Remove(SerializationObject serializationObject)
        {
            if (serializationObject == null)
                throw new ArgumentNullException("serializationObject");

            if (serializationObject is Font)
                this.Fonts.Remove((Font)serializationObject);
            if (serializationObject is LayoutFrame)
                this.LayoutFrames.Remove((LayoutFrame)serializationObject);
        }

        /// <summary>
        /// Resets the item.
        /// </summary>
        /// <param name="layoutFrame">The layout frame.</param>
        public void ResetItem(LayoutFrame layoutFrame)
        {
            this.LayoutFrames.ResetItem(layoutFrame);
        }

        /// <summary>
        /// Gets the child serialization objects.
        /// </summary>
        /// <param name="includeInherited">A value indicating whether to include the inherited serialization objects.</param>
        /// <returns></returns>
        IEnumerable<SerializationObject> ISerializationObjectContainer.GetChildren(bool includeInherited)
        {
            return fonts.Cast<SerializationObject>().Concat(layoutFrames.Cast<SerializationObject>());
        }

        /// <summary>
        /// Initializes the parents of the layout frames in the hierarchy.
        /// </summary>
        public void InitializeParent()
        {
            foreach (var layoutFrame in layoutFrames)
                layoutFrame.InitializeParent(null, true);
        }
        
        /// <summary>
        /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </returns>
        public override string ToString()
        {
            return "Ui";
        }
    }
}